package org.tea.mapper.util;

import cn.hutool.core.lang.Pair;
import cn.hutool.core.util.ReflectUtil;
import org.apache.ibatis.builder.annotation.ProviderContext;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.LogFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 *@author lxh
 */
public class BaseInsertMapperProvider
        extends MapperHelper {

    private final static Log log = LogFactory.getLog(BaseInsertMapperProvider.class);

    public String insert(Object param, ProviderContext providerContext) {
        Class<?> mapperType = providerContext.getMapperType();
        Class<?> entityType = parseActualEntityType(mapperType);
        String tableName = parseTableName(entityType);

        Map<Pair<String, Class<?>>, String> field2Column = buildField2Column(entityType);
        StringBuilder insertSqlBuilder = buildInsertCommon(tableName, field2Column);
        List<String> values = convertToInsertValues(param, field2Column);
        insertSqlBuilder.append(" (").append(String.join(", ", values))
                .append(")");
        log.trace(String.format("insert sql: %s", insertSqlBuilder));
        return insertSqlBuilder.toString();
    }

    public String insertSelective(Object param, ProviderContext providerContext) {
        return insert(param, providerContext);
    }

    public String insertBatch(List<?> rowList, ProviderContext providerContext) {
        Class<?> mapperType = providerContext.getMapperType();
        Class<?> entityType = parseActualEntityType(mapperType);
        String tableName = parseTableName(entityType);

        Map<Pair<String, Class<?>>, String> field2Column = buildField2Column(entityType);
        StringBuilder insertBatchSqlBuilder = buildInsertCommon(tableName, field2Column);
        List<String> valuesList = new ArrayList<>();
        for (Object row : rowList) {
            valuesList.add("(" + String.join(", ", convertToInsertValues(row, field2Column)) + ")");
        }
        insertBatchSqlBuilder.append(String.join(", ", valuesList));
        log.trace(String.format("insertBatch sql: %s", insertBatchSqlBuilder));
        return insertBatchSqlBuilder.toString();
    }

    public String insertSelectiveBatch(List<?> rowList, ProviderContext providerContext) {
        return insertBatch(rowList, providerContext);
    }

    private static StringBuilder buildInsertCommon(String tableName, Map<Pair<String, Class<?>>, String> field2Column) {
        StringBuilder insertSqlBuilder = new StringBuilder();
        insertSqlBuilder.append("INSERT INTO ").append(tableName)
                .append(" (").append(String.join(", ", field2Column.values()))
                .append(") ").append(" VALUES ");
        return insertSqlBuilder;
    }

    private List<String> convertToInsertValues(Object param, Map<Pair<String, Class<?>>, String> field2Column) {
        List<String> values = new ArrayList<>();
        for (Map.Entry<Pair<String, Class<?>>, String> entry : field2Column.entrySet()) {
            Pair<String, Class<?>> pair = entry.getKey();
            Object val = ReflectUtil.getFieldValue(param, pair.getKey());
            if (val == null) {
                values.add("null");
                continue;
            }

            values.add("'" + convertObjValToStr(val) + "'");
        }
        return values;
    }
}
